﻿#ifndef MEASUREELEMENT_H
#define MEASUREELEMENT_H

#include <QPointF>
#include <QVector>
#include <QPen>
#include <QFont>
#include <QDebug>
#include "MeasureView/TextBlock.h"
#include "MeasureView/UnitConvert.h"
#include "MeasureView_global.h"

namespace Qly {

class MeasureDataSet;

/**
 * @brief The MeasureElement class 所有测量元素的公共基类。提供了一些公用的方法。比如设置颜色、字号等。
 */
class MEASUREVIEW_EXPORT MeasureElement
{
    friend MeasureDataSet;
public:
    enum ElementType{ None,
                   Line, // 点到点的距离
                   Polyline,  // 折线的总长度
                   Angle3P, // 三点夹角
                   Angle4P,  //直线到直线的夹角
                   ParallelLine, // 平行线间的距离
                   LineWidth_SA, // 平行线间的距离
                   CircleCenter, // 圆测量，圆心和圆上一点
                   CircleCenter_SA,
                   Circle2P, // 圆测量，直径上两个端点
                   Circle2P_SA,
                   Circle3P,  // 圆测量，圆上三点
                   Circle2Circle,  // 圆心到圆心距离，圆上三点-圆上三点
                   Arc3P,  // 圆弧测量，圆弧上三点
                   Polygon,  // 多边形面积
                   Rect,  // 矩形面积
                   Dots2Line, // 点到直线的距离
                   Count, // 计数
                   Delete
                 };
    enum ElementType type() const;
    QString typeString() const;
    virtual QString name() = 0; //返回当前对象的中文名称
    enum MeasureState {DS_IDLE, DS_STATE1, DS_STATE2, DS_STATE3, DS_STATE4, DS_STATE5, DS_STATE6, DS_FINISH, DS_ERROR};
    enum MeasureState state() const;
    /**
     * @brief setPen 设置线条的宽度、颜色等。
     * @param pen
     */
    void setPen(const QPen &pen);
    void setLineWidth(int width);
    void setLineColor(QRgb rgb);
    /**
     * @brief setFont 设置字体。测量结果显示的文字使用这个字体。
     * @param font
     */
    void setFont(const QFont &font);

    /**
     * @brief id 返回当前图元的 ID 号
     * @return
     */
    int id() const { return m_id;}

    /**
     * @brief results 返回测量结果。不同的子类，测量结果的存储方式是不同的。具体请参考派生类的介绍。
     * @return
     */
    const QVector<double> & results() const;
    const QVector<double> & results_pix() const;
    const QVector<QPointF> & keyPoints_pix() const;


    void setTemplate(QString str);
    void setID(int id) {m_id = id;}
    MeasureElement(MeasureDataSet *pParent = nullptr);
    virtual ~MeasureElement() {}
protected:
    virtual void textMove(const QPointF & offset_pix, const QPointF & offset_um); // 移动文字
    virtual bool isInTextBox(const QPointF & point);
    virtual void paint(QPainter &painter) = 0; // paintEvent 事件里调用。
    virtual int mouseLButtonPress(QPointF point_pix, QPointF point_um) = 0; // 鼠标左键按下时调用这个成员函数
    virtual int mouseLButtonRelease(QPointF point_pix, QPointF point_um); // 鼠标左键抬起时调用这个函数，如果返回非 0 值，则需要刷新界面
    virtual int mouseRButtonPress(QPointF point_pix, QPointF point_um); // 鼠标右键按下时调用。
    virtual int mouseMove(QPointF point_pix, QPointF point_um); // 鼠标移动时调用。

    virtual int setPixelSize(double newPixelSize_um, int method);
    virtual void updatePixelSize(double pixelsize_um);
    virtual void compute() = 0;
    virtual void updateText(bool updatePosition = true) = 0;
    enum DeleteResult {DeleteNothing, DeleteByMyself, DeleteByOther};
    virtual DeleteResult tryDelete(QPointF p); // 检查是否需要删除当前对象，DeleteByMyself 表示自己已经内部删除了， DeleteByOther 表示需要外部删除，DeleteNothing 不删除
    void drawCross(QPainter &painter, QPointF p);
    void finish(); //  强行终止这个测量
protected:
    MeasureDataSet *m_pParent = nullptr;
    QFont m_font;  //文字的字体
    QPen m_pen;//线的颜色
    ElementType m_measureType; // 记录当前是哪种测量。
    MeasureState m_measureState; // 记录当前测量到哪步了。
    QVector<double> m_results_pix; //测量的结果，单位是pix 或者 pix^2。
    QVector<double> m_results_um; // 测量的结果，单位是 um 或者 um^2。对于角度等非长度测量，结果与 m_results_pix 相同。
    QVector<QPointF> m_keyPoints_pix; // 测点在图像坐标系下的坐标。图像以中心为原点（0，0）。以像素为单位。
    QVector<QPointF> m_keyPoints_um; // 测点在显微镜坐标系下的坐标。以显微镜中心为原点（0，0）。以 um 为单位。

    TextBlock m_textBlock;
    bool m_textMoving = false;
    QString m_textTemplate;
    int m_id; //每个 Element 都有一个唯一的 id
    QString m_name; // 返回这个测量元素的名称
};


QString type2String(const MeasureElement::ElementType &t);
QDebug operator<<(QDebug dbg, const MeasureElement::ElementType &t);
QDebug operator<<(QDebug dbg, const MeasureElement::MeasureState &t);


}

#endif // MEASUREELEMENT_H
